"""AJAX Handler class."""

import json
import logging
import tornado.web
import yaml
from gaweb import consts
from gaweb.master import excepts
from gaweb.master import helpers


class AjaxHandler(tornado.web.RequestHandler):
    """Ajax Request Handler for the /ajax path"""

    def initialize(self, master):
        self.master = master

    def get(self):
        task = self.get_argument('task')
        try:
            # Session creation and deletion
            if task == 'init':
                self.handle_init()
            elif task == 'end':
                self.handle_end()

            # Actions that can happen during lifetime
            elif task == 'command':
                self.handle_command()
            elif task == 'nodestats':
                self.handle_nodestats()
            elif task == 'ping':
                self.handle_ping()
            elif task == 'varinfo':
                self.handle_varinfo()
            else:
                self.write('Unknown task "%s"' % task)
        except Exception, e:
            logging.error(e)
            self.write(json.dumps({'task': task,
                                   'error': -1,
                                   'message': 'Unknown error.'}))

    def handle_init(self):
        """Handle initialization of the client. Creates a new session and returns
        the session id.

        Error numbers:
          1 -> the connecting IP address has surpassed the max session limit
        """
        try:
            session_id = self.master.make_session(self.request.remote_ip)
        except excepts.SessionLimitReached:
            session_id = None

        if session_id is None:
            logging.warning('Session limit reached for ip_addr = %s' % self.request.remote_ip)
            self.write(json.dumps({'task': 'init',
                                   'error': 1}))
        else:
            logging.info('Handling init; made new session %s' % session_id)
            try:
                menu = helpers.read_config('menu.yaml')
            except IOError:
                menu = None
            except yaml.parser.ParserError:
                menu = None
            except:
                menu = None

            self.write(json.dumps({'task': 'init',
                                   'menu': menu,
                                   'session_id': session_id,
                                   'ping_interval': consts.JS_PING_INTERVAL}))

    def handle_end(self):
        """Handles a request to end a session. Calls method in the master to
        end the session.

        Error numbers:
          1 -> session not found in master's server dictionary
        """
        session_id = self.get_argument('session_id')
        
        try:
            self.master.end_session(session_id)
            self.write({'task': 'end'})
        except excepts.SessionError:
            self.write({'task': 'end',
                        'error': 1,
                        'message': 'Session not ended because it was not found.'})

    def handle_command(self):
        """Handles a command.
        Error numbers:
          1 -> session not found in master's server dictionary
          2 -> node disconnected
        """
        session_id = self.get_argument('session_id')
        command = self.get_argument('command')

        logging.debug('Handling command %s' % repr(command))
        
        try:            
            command_resp = self.master.handle_command(session_id, command)

            self.write({'task': 'command',
                        'output': command_resp.output,
                        'image': command_resp.image,
                        'image_data': command_resp.image_data,
                        'files_changed': command_resp.files_changed,
                        'dims_changed': command_resp.dims_changed,
                        'dims': command_resp.dims,
                        'ctlinfo': command_resp.ctlinfo,
                        'display_expr_changed': command_resp.display_expr_changed,
                        'display_expr': command_resp.display_expr,
                        'done': True})
        except excepts.SessionError:
            self.write({'task': 'command',
                        'error': 1,
                        'message': 'Session not found.'})
        except excepts.NodeConnectionError:
            self.write({'task': 'command',
                        'error': 2,
                        'message': 'Node disconnected'})
 
    def handle_gettemplate(self):
        """Handles the frontent requesting a template.
        Args:
          template_id: the id string of the template
        Error numbers:
          1 -> template not found
        """
        template_id = self.get_argument('template_id')
        if template_id in self.templates:
            template = self.templates[template_id]
            self.write({'task': 'gettemplate',
                        'template': template})
        else:
            self.write({'task': 'gettemplate',
                        'error': 1})

    def handle_nodestats(self):
        """Handles a request to see node stats for a session.

        Error numbers: 
          1 -> session not found in master's server dictionary
          2 -> node disconnected
        """
        session_id = self.get_argument('session_id')

        try:
            text = self.master.handle_nodestats(session_id)
            self.write({'task': 'nodestats',
                        'text': text})
        except excepts.SessionError:
            self.write({'task': 'nodestats',
                        'error': 1})
        except excepts.NodeConnectionError:
            self.write({'task': 'command',
                        'error': 2,
                        'message': 'Node disconnected'})
            
    def handle_ping(self):
        """Handles a ping.
        Error numbers:
          1 -> session not found in master's server dictionary
          2 -> node disconnected
        """
        session_id = self.get_argument('session_id')
        try:
            self.master.handle_ping(session_id)
            self.write({'task': 'ping'})
        except excepts.SessionError:
            self.write({'task': 'ping',
                        'error': 1})
        except excepts.NodeConnectionError:
            self.write({'task': 'command',
                        'error': 2,
                        'message': 'Node disconnected'})
    
    def handle_varinfo(self):
        """Handles a varinfo request.
        Error numbers:
          1 -> session not found in master's server dictionary
        """

        session_id = self.get_argument('session_id')

        try:
            files = self.master.handle_varinfo(session_id)
            self.write({'task': 'varinfo',
                        'var_info': files})
        except excepts.SessionError:
            self.write({'task': 'varinfo',
                        'error': 1})

